package com.daona.job.service.impl;

import cn.hutool.core.io.FileUtil;
import com.daona.job.service.PdfService;
import com.daona.model.template.PdfModel;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.lowagie.text.pdf.BaseFont;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;

@Service
@RequiredArgsConstructor
@Slf4j
public class PdfServiceImpl implements PdfService {

    private final TemplateEngine templateEngine;

    private final Executor threadPoolExecutor;

    @Value("${daona.pdf.folder}")
    private String folder;

    @Value("${daona.pdf.output}")
    private String output;

    /**
     * 生成HTML内容
     * @return 渲染后的HTML字符串
     */
    private String generateHtmlContent(String templateName, Object data) {
        if(StringUtils.hasText(templateName)) {
            Context context = new Context();
            context.setVariable(templateName, data);
            return templateEngine.process(templateName, context);
        }
        return null;
    }

    public Map<String,String> getPdfByFolder() throws Exception {
        return getPdfByFolder(folder);
    }

    public Map<String,String> getPdfByFolder(String folder) throws Exception {
        if(!FileUtil.exist(folder)){
            throw new Exception("file folder does not exist");
        }
        Map<String, String> sortedFiles = Maps.newTreeMap();
        List<File> files = FileUtil.loopFiles(folder);
        files.forEach(file -> {
            String prefix = file.getName().split("\\.")[0];
            sortedFiles.put(prefix, output + "/" + prefix + ".pdf");
        });
        return sortedFiles;
    }

    public List<String> generateMultiplePdf(PdfModel data) throws Exception {
        Map<String,String> templates = getPdfByFolder();
        CountDownLatch countDownLatch = new CountDownLatch(templates.size());
        ArrayList<@Nullable String> pdfList = Lists.newArrayList();

        for (Map.Entry<String, String> entry : templates.entrySet()) {
            threadPoolExecutor.execute(() -> {
                try {
                    pdfList.add(entry.getValue());
                    htmlToPdf(entry.getValue(), entry.getKey(), data);
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        countDownLatch.await();
        log.info("======= generate pdf successfully =======");
        return pdfList;
    }

    private void htmlToPdf(String output, String templateName, PdfModel data) throws Exception {
        // 创建ITextRenderer实例
        ITextRenderer renderer = new ITextRenderer();
        // 设置字体路径，使用 classpath 加载字体
        ITextFontResolver fontResolver = renderer.getFontResolver();
        fontResolver.addFont("static/font/SimSun.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        String htmlContent = generateHtmlContent(templateName, data);
        if(StringUtils.hasText(htmlContent)) {
            renderer.setDocumentFromString(htmlContent);
            renderer.layout();
            if (FileUtil.exist(output)) {
                FileUtil.del(FileUtil.file(output));
            }
            // 输出PDF到响应输出流
            renderer.createPDF(new FileOutputStream(FileUtil.file(output)));
            log.info(output);
        }
    }

    public void mergePdf(List<String> pdfs, String output) {
        try {
            PDFMergerUtility pdfMerger = new PDFMergerUtility();
            pdfs.forEach(p -> {
                try {
                    pdfMerger.addSource(p);
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            });
            pdfMerger.setDestinationFileName(output);
            pdfMerger.mergeDocuments(null);
            log.info("merge pdf successfully {}", output);

        }catch (Exception e){
            log.error(e.getMessage());
        }
    }

}
